import cv2
import numpy as np
import pyautogui
import win32gui
import win32con
import win32api
import time
import sys
import os

# 尝试导入 fight_module，如果不存在则会发出警告
try:
    import fight_module
except ImportError:
    print("警告: fight_module.py 未找到。部分功能可能受限。")
    fight_module = None

# TEMPLATE_DIR 的定义保持不变，确保模板路径正确
# 使用 sys.executable 获取当前运行的 Python 解释器的路径，然后获取其所在目录
# 这样可以更稳健地找到脚本的真实位置，即使脚本被打包成exe
if getattr(sys, 'frozen', False):
    # 如果是打包的exe文件
    BASE_DIR = os.path.dirname(sys.executable)
else:
    # 如果是普通的.py文件
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))

TEMPLATE_DIR = os.path.join(BASE_DIR, "templates")

# 预加载模板字典，以避免重复读取和转换
# 键为模板文件名，值为对应的灰度图模板
_template_cache = {}


def template_path(filename):
    """构建模板图像的完整路径。"""
    return os.path.join(TEMPLATE_DIR, filename)


def find_window(title_part):
    """根据窗口标题的一部分查找窗口句柄。"""

    def enum_callback(hwnd, result):
        if win32gui.IsWindowVisible(hwnd) and title_part in win32gui.GetWindowText(hwnd):
            result.append(hwnd)

    result = []
    win32gui.EnumWindows(enum_callback, result)
    return result[0] if result else None


def set_foreground(hwnd):
    """将指定窗口置于前台。"""
    win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
    win32gui.SetForegroundWindow(hwnd)
    time.sleep(0.5)


def get_window_rect(hwnd):
    """获取窗口的矩形区域（左、上、右、下坐标）。"""
    return win32gui.GetWindowRect(hwnd)


def screenshot_window(hwnd):
    """对指定窗口进行截图。"""
    left, top, right, bottom = get_window_rect(hwnd)
    width, height = right - left, bottom - top
    screenshot = pyautogui.screenshot(region=(left, top, width, height))
    return cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR), (left, top)


def match_template(img, template_path_str, threshold=0.8):  # 默认阈值与下面保持一致
    """
    在大图中查找模板图像。
    优化点1：模板和待搜索图像都转换为灰度图进行匹配，提高鲁棒性。

    参数：
        img (numpy.array): 要搜索的大图（彩色BGR格式）。
        template_path_str (str): 模板图像的文件路径。
        threshold (float): 匹配的最低相似度阈值。

    返回：
        tuple: 如果找到匹配项，返回 (匹配位置, 模板宽度, 模板高度)；
               否则返回 (None, 0, 0)。
    """
    # 从缓存获取模板，如果不存在则加载并转换为灰度图
    if template_path_str not in _template_cache:
        template_color = cv2.imread(template_path_str, cv2.IMREAD_COLOR)
        if template_color is None:
            print(f"模板图像 {template_path_str} 读取失败")
            return None, 0, 0
        _template_cache[template_path_str] = cv2.cvtColor(template_color, cv2.COLOR_BGR2GRAY)

    template_gray = _template_cache[template_path_str]

    # 将输入的图像也转换为灰度图
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    result = cv2.matchTemplate(img_gray, template_gray, cv2.TM_CCOEFF_NORMED)
    _, max_val, _, max_loc = cv2.minMaxLoc(result)

    # 可以在调试时打印 max_val，帮助调整阈值
    # print(f"匹配 {os.path.basename(template_path_str)} 的最大匹配值为: {max_val:.2f}")

    if max_val >= threshold:
        return max_loc, template_gray.shape[1], template_gray.shape[0]
    return None, 0, 0


def click_at(x, y):
    """移动鼠标到指定坐标并点击。"""
    pyautogui.moveTo(x, y)
    pyautogui.click()


def press_j():
    """模拟按下 'J' 键。"""
    win32api.keybd_event(0x4A, 0, 0, 0)  # 0x4A 是 'J' 键的虚拟键码
    time.sleep(0.05)
    win32api.keybd_event(0x4A, 0, win32con.KEYEVENTF_KEYUP, 0)


def find_and_click(hwnd, template_name, desc="", threshold=0.7):  # 保持 0.7 阈值
    """
    在窗口截图中查找模板并点击其中心。

    参数：
        hwnd (int): 窗口句柄。
        template_name (str): 模板图像的文件名。
        desc (str): 用于日志输出的描述信息。
        threshold (float): 匹配阈值。**请根据实际测试，调整此值以达到最佳效果。**

    返回：
        bool: 如果找到并点击了模板，则返回 True；否则返回 False。
    """
    path = template_path(template_name)
    screen_img, offset = screenshot_window(hwnd)

    # 显式传递阈值
    match_pos, w, h = match_template(screen_img, path, threshold)

    if match_pos:
        x, y = match_pos
        screen_x = offset[0] + x + w // 2
        screen_y = offset[1] + y + h // 2
        click_at(screen_x, screen_y)
        print(f"已点击 {desc or template_name}")
        return True
    else:
        print(f"未找到 {desc or template_name}")
        return False


def drag_left(hwnd, distance=1000):
    """在窗口内执行向左拖动操作。"""
    left, top, right, bottom = get_window_rect(hwnd)
    y = top + (bottom - top) // 2
    start_x = right - 100
    end_x = start_x - distance
    pyautogui.moveTo(start_x, y)
    pyautogui.mouseDown()
    pyautogui.moveTo(end_x, y, duration=0.3)
    pyautogui.mouseUp()
    print("已向左滑动一次")
    time.sleep(1)


def find_target_with_drag(hwnd, template_name, max_attempts=10, threshold=0.7):  # 默认阈值与 find_and_click 保持一致
    """
    查找目标模板，如果需要则执行向左拖动。

    参数：
        hwnd (int): 窗口句柄。
        template_name (str): 模板图像的文件名。
        max_attempts (int): 最大拖动尝试次数。
        threshold (float): 匹配阈值。**请根据实际测试，调整此值以达到最佳效果。**

    返回：
        bool: 如果找到并点击了目标，则返回 True；否则返回 False。
    """
    path = template_path(template_name)
    for i in range(max_attempts):
        screen_img, offset = screenshot_window(hwnd)

        # 显式传递阈值
        match_pos, w, h = match_template(screen_img, path, threshold)

        if match_pos:
            x, y = match_pos
            screen_x = offset[0] + x + w // 2
            screen_y = offset[1] + y + h // 2
            click_at(screen_x, screen_y)
            print(f"第{i + 1}次滑动后找到并点击目标图标：{template_name}")
            return True
        else:
            drag_left(hwnd)
    print(f"未在滑动中找到目标图标：{template_name}")
    return False


def automate_aether_gazer_workflow():
    """
    自动化《深空之眼》(AetherGazer) 游戏中的特定工作流程。
    此函数可以直接运行，也可以作为模块被其他文件导入和调用。

    返回：
        bool: 如果自动化流程成功完成，则返回 True；否则返回 False。
    """
    # 查找游戏窗口
    hwnd = find_window("AetherGazer")
    if not hwnd:
        print("未找到 AetherGazer 游戏窗口。")
        return False

    # 将游戏窗口置于前台并按下 J 键
    set_foreground(hwnd)
    time.sleep(1.5)
    press_j()
    print("已按下j键")

    # 点击“挑战”图标 - 使用 0.7 阈值
    time.sleep(1.5)
    if not find_and_click(hwnd, "challenge.png", "挑战图标", threshold=0.75):
        return False

    time.sleep(1.5)

    # 点击“历战轮回”图标 - 使用 0.7 阈值
    if not find_and_click(hwnd, "LiZhanLunHui.png", "历战轮回图标", threshold=0.7):
        return False

    time.sleep(2)

    # 拖动并查找目标图标 - 使用 0.7 阈值
    if not find_target_with_drag(hwnd, "target.png", max_attempts=8, threshold=0.7):
        return False

    time.sleep(2)

    # 新页面中点击 "ten.png" - 使用 0.7 阈值
    if not find_and_click(hwnd, "ten.png", "ten 图标", threshold=0.7):
        return False

    time.sleep(1.5)

    # 点击 "fight_start.png" - 使用 0.7 阈值
    if not find_and_click(hwnd, "fight_start.png", "开始战斗", threshold=0.7):
        return False

    time.sleep(2)

    # 按下 Enter 键
    win32api.keybd_event(win32con.VK_RETURN, 0, 0, 0)
    time.sleep(0.05)
    win32api.keybd_event(win32con.VK_RETURN, 0, win32con.KEYEVENTF_KEYUP, 0)
    print("已按下回车键。")

    # 调用 fight_module 中的自动化功能
    if fight_module:
        fight_module.run_game_automation()
    else:
        print("跳过 fight_module.run_game_automation()，因为 fight_module 未导入。")

    return True


# --- 程序的入口点 ---
if __name__ == "__main__":
    # 只有当此脚本被直接运行时，才会执行此处的代码
    print("正在启动《深空之眼》自动化流程...")
    if automate_aether_gazer_workflow():
        print("《深空之眼》自动化流程成功完成。")
    else:
        print("《深空之眼》自动化流程失败或被中断。")